/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package x2rel.qMap.core;

import java.io.ByteArrayInputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;


import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.TransformerConfigurationException;
import x2rel.qMap.logger.Logging;

//Java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Properties;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;

//SAXON
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.Configuration;
import net.sf.saxon.query.DynamicQueryContext;
import net.sf.saxon.query.StaticQueryContext;
import net.sf.saxon.query.XQueryExpression;
import org.xml.sax.InputSource;

/**
 *
 * @author Leonardo Nicorena <lnicorena at inf.ufsm.br>
 */
public class Utils {

    public static String dump(Object o) {
        StringBuffer buffer = new StringBuffer();
        Class oClass = o.getClass();
        if (oClass.isArray()) {
            buffer.append("Array: ");
            buffer.append("[");
            for (int i = 0; i < Array.getLength(o); i++) {
                Object value = Array.get(o, i);
                if (value.getClass().isPrimitive()
                        || value.getClass() == java.lang.Long.class
                        || value.getClass() == java.lang.Integer.class
                        || value.getClass() == java.lang.Boolean.class
                        || value.getClass() == java.lang.String.class
                        || value.getClass() == java.lang.Double.class
                        || value.getClass() == java.lang.Short.class
                        || value.getClass() == java.lang.Byte.class) {
                    buffer.append(value);
                    if (i != (Array.getLength(o) - 1)) {
                        buffer.append(",");
                    }
                } else {
                    buffer.append(dump(value));
                }
            }
            buffer.append("]\n");
        } else {
            buffer.append("Class: " + oClass.getName());
            buffer.append("{\n");
            while (oClass != null) {
                Field[] fields = oClass.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    buffer.append(fields[i].getName());
                    buffer.append("=");
                    try {
                        Object value = fields[i].get(o);
                        if (value != null) {
                            if (value.getClass().isPrimitive()
                                    || value.getClass() == java.lang.Long.class
                                    || value.getClass() == java.lang.String.class
                                    || value.getClass() == java.lang.Integer.class
                                    || value.getClass() == java.lang.Boolean.class
                                    || value.getClass() == java.lang.Double.class
                                    || value.getClass() == java.lang.Short.class
                                    || value.getClass() == java.lang.Byte.class) {
                                buffer.append(value);
                            } else {
                                buffer.append(dump(value));
                            }
                        }
                    } catch (IllegalAccessException e) {
                        buffer.append(e.getMessage());
                    }
                    buffer.append(";\n");
                }
                oClass = oClass.getSuperclass();
            }
            buffer.append("}\n");
        }
        return buffer.toString();
    }

    public static String runXquery(File source, String xq) {
        //Logging.getInstance().log("File!!!\n"+readFile(source),3);
        return runXquery(readFile(source), xq);
    }

    public static String runXquery(String source, String xq) {

        String saida = "";

        Logging.getInstance().log("XQuery executada:\n" + xq);
//
//        // Xml file
//        File XMLStream = source;

        //compile the XQuery expression
        XQueryExpression exp = null;

        //create a Configuration object
        Configuration C = new Configuration();

        //static and dynamic context
        StaticQueryContext SQC = new StaticQueryContext(C);
        DynamicQueryContext DQC = new DynamicQueryContext(C);

        //indentation
        Properties props = new Properties();
        props.setProperty(OutputKeys.METHOD, "xml");
        props.setProperty(OutputKeys.INDENT, "yes");

        try {

            //compilation
            exp = SQC.compileQuery(xq);
            //SQC = exp.getStaticContext();
        } catch (net.sf.saxon.trans.XPathException e) {
            System.err.println(e.getMessage());
        }
//        catch (java.io.IOException e) {
//            System.err.println(e.getMessage());
//        }

        //get the XML ready
        try {

            //XMLStream = new File(xmlFileName);
            //InputSource XMLSource = new InputSource(XMLStream.toURI().toString());
            InputSource XMLSource = new InputSource(new StringReader(source));
            SAXSource SAXs = new SAXSource(XMLSource);
            DocumentInfo DI = SQC.buildDocument(SAXs);
            DQC.setContextNode(DI);

            //evaluating
//            exp.run(DQC, new StreamResult(destStream), props);
//            destStream.close();


            //saida em string
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StreamResult result = new StreamResult(new StringWriter());
            exp.run(DQC, result, props);
            //DOMSource source = new DOMSource(new Doc);
            //transformer.transform(source, result);
            saida = result.getWriter().toString();



        } catch (net.sf.saxon.trans.XPathException e) {
            System.err.println(e.getMessage());
        } catch (TransformerConfigurationException e) {
            System.err.println(e.getMessage());
        } catch (TransformerException e) {
            System.err.println(e.getMessage());
        }


        return saida;

    }

    private static String readFile(File f) {
        try {
            //FileInputStream stream = new FileInputStream(new File(path));
            FileInputStream stream = new FileInputStream(f);
            try {
                FileChannel fc = stream.getChannel();
                MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
                /* Instead of using default, pass in a decoder. */
                return Charset.defaultCharset().decode(bb).toString();
            } finally {
                stream.close();
            }
        } catch (IOException ex) {

            return "";
        }

    }

    /*
     * Quantas vezes uma strng s aparece em source
     */
    public Integer countStr(String source, String s) {
        Integer i = 0;
        Integer k;
        k = source.indexOf(s);
        
        while(k != -1){
            i++;
            source = source.substring(k+1);
            k = source.indexOf(s);
        }
        
        return i;
    }
    
    public Variables getVarByCod(ArrayList<Variables> vars, Integer cod){
        
        for(Variables v : vars){
            if(v.getCod().equals(cod))
                return v;
        }
        
        return null;
    }
}
